﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace MapEditor
{
    public partial class Form1 : Form
    {
        int tileWH = 128; // Tile Width and Height
        Point[,] LevelGrid = new Point[20, 10];
        Size tileSize;
        Point selectedTile = new Point(0, 0);
        Size totalLevelSize;
        List<TileClass> list = new List<TileClass>();

        // Player's Position Info
        Point playerPos = new Point(0, 0);
        Bitmap playerImage = new Bitmap(Properties.Resources.Player);

        public Form1()
        {
            InitializeComponent();

            tileSize = new Size(tileWH, tileWH);
            totalLevelSize = new Size(tileWH * 20, tileWH * 10);

            LevelPanel.AutoScrollMinSize = new Size(LevelGrid.GetLength(0) * tileSize.Width, LevelGrid.GetLength(1) * tileSize.Height);
            gridX.Value = LevelGrid.GetLength(0);
            gridY.Value = LevelGrid.GetLength(1);
        
            tileWH_numBox.Value = tileWH;

            // IF you add another object
            // go to this function --> objectList_SelectedIndexChanged
            // and make sure we select the correct object there too
            objectList.Items.Add("Block");
            objectList.Items.Add("Checkpoint Flag");
            objectList.Items.Add("Floor");
            objectList.Items.Add("Jump Box");
            objectList.Items.Add("Launch Cannon");
            objectList.Items.Add("Ramp");
            objectList.Items.Add("Spike");
            objectList.Items.Add("Turret");



            objectList.SelectedIndex = 2;
        }

        private void LevelPanel_Paint(object sender, PaintEventArgs e)
        {
            Point offset = Point.Empty;
            offset.X += LevelPanel.AutoScrollPosition.X;
            offset.Y += LevelPanel.AutoScrollPosition.Y;
            
            Rectangle selRect = Rectangle.Empty;

            Pen pen = new Pen(Color.Black, 1.0f);
            int x, y;
            for (x = 0; x < LevelGrid.GetLength(0); x++)
            {
                for (y = 0; y < LevelGrid.GetLength(1); y++)
                {
                    Rectangle destRect = Rectangle.Empty;

                    destRect.X = x * tileSize.Width;
                    destRect.Y = y * tileSize.Height;
                    destRect.Size = tileSize;
                    destRect.Offset(LevelPanel.AutoScrollPosition);

                    if (e.Graphics.IsVisible(destRect))
                    {
                        Rectangle srcRect = Rectangle.Empty;
                        srcRect.X = LevelGrid[x, y].X * tileSize.Width;
                        srcRect.Y = LevelGrid[x, y].Y * tileSize.Height;
                        srcRect.Size = tileSize;

                        e.Graphics.DrawRectangle(pen, destRect);
                    }
                }
            }
            pen.Dispose();

            Pen selPen = new Pen(Color.Wheat, 5f);
            selRect.X = selectedTile.X * tileSize.Width;
            selRect.Y = selectedTile.Y * tileSize.Height;
            selRect.Size = tileSize;
            selRect.Offset(LevelPanel.AutoScrollPosition);
            e.Graphics.DrawRectangle(selPen, selRect);
            selPen.Dispose();
               
            int offsetX = LevelPanel.AutoScrollPosition.X;
            int offsetY = LevelPanel.AutoScrollPosition.Y;

            // Drawing all tiles in our list
            if (list.Count > 0)
            {   
                // To see what we have in the list and render what is there
                for (int i = 0; i < list.Count(); i++)
                {
                    e.Graphics.DrawImage(list.ElementAt<TileClass>(i).Bitmap, list.ElementAt<TileClass>(i).Pos.X + offsetX, list.ElementAt<TileClass>(i).Pos.Y + offsetY);
                }
            }

            // Drawing the player's position
            e.Graphics.DrawImage(playerImage, playerPos.X + offsetX, playerPos.Y + offsetY);

            // Do NOT put int the paint method!!!!
            // Crashes all Message Boxes!!!!!
            // LevelPanel.Invalidate();
        }

        private void LevelPanel_MouseClick(object sender, MouseEventArgs e)
        {
            if (playerCheck.Checked == false)
            {
                if (e.Button == MouseButtons.Left)
                {
                    if (e.Location.X < totalLevelSize.Width && e.Location.Y < totalLevelSize.Height)
                    {
                        Point offset = e.Location;
                        offset.X -= LevelPanel.AutoScrollPosition.X;
                        offset.Y -= LevelPanel.AutoScrollPosition.Y;
                        selectedTile.X = offset.X / tileSize.Width;
                        selectedTile.Y = offset.Y / tileSize.Height;
                        TileClass newTile = new TileClass();
                        newTile.Pos = new Point(selectedTile.X * tileWH, selectedTile.Y * tileWH);
                        newTile.Bitmap = (Bitmap)pictureBox.Image;
                        newTile.Type = objectList.SelectedIndex;
                        if (newTile.Pos.X != playerPos.X || newTile.Pos.Y != playerPos.Y)
                        {
                            if (list.Count > 0)
                            {
                                int listSize = list.Count() - 1;
                                // To see what we have in the list and remove it if we have a tile where we clicked
                                for (int i = listSize; i > -1; i--)
                                {
                                    int tempCheckX = list.ElementAt<TileClass>(i).Pos.X / tileWH;
                                    int tempCheckY = list.ElementAt<TileClass>(i).Pos.Y / tileWH;

                                    if (tempCheckX == selectedTile.X && tempCheckY == selectedTile.Y)
                                    {
                                        list.RemoveAt(i);
                                    }
                                }
                            }

                            list.Add(newTile);
                            LevelPanel.Invalidate();
                        }
                    }
                }

                if (e.Button == MouseButtons.Right)
                {
                    // For removing where we clicked
                    if (e.Location.X < totalLevelSize.Width && e.Location.Y < totalLevelSize.Height && list.Count > 0)
                    {
                        Point offset = e.Location;
                        offset.X -= LevelPanel.AutoScrollPosition.X;
                        offset.Y -= LevelPanel.AutoScrollPosition.Y;
                        selectedTile.X = offset.X / tileSize.Width;
                        selectedTile.Y = offset.Y / tileSize.Height;

                        int listSize = list.Count() - 1;
                        // To see what we have in the list and remove it if we have a tile where we clicked
                        for (int i = listSize; i > -1; i--)
                        {
                            int tempCheckX = list.ElementAt<TileClass>(i).Pos.X / tileWH;
                            int tempCheckY = list.ElementAt<TileClass>(i).Pos.Y / tileWH;

                            if (tempCheckX == selectedTile.X && tempCheckY == selectedTile.Y)
                            {
                                list.RemoveAt(i);
                            }
                        }
                        LevelPanel.Invalidate();
                    }
                }
            }
            else // Button clicks will set player's pos
            {
                if (e.Location.X < totalLevelSize.Width && e.Location.Y < totalLevelSize.Height)
                {
                    Point offset = e.Location;
                    offset.X -= LevelPanel.AutoScrollPosition.X;
                    offset.Y -= LevelPanel.AutoScrollPosition.Y;
                    selectedTile.X = offset.X / tileSize.Width;
                    selectedTile.Y = offset.Y / tileSize.Height;

                    playerPos = new Point(selectedTile.X * tileWH, selectedTile.Y * tileWH);

                    if (list.Count > 0)
                    {
                        int listSize = list.Count() - 1;
                        // To see what we have in the list and remove it if we have a tile where we clicked
                        for (int i = listSize; i > -1; i--)
                        {
                            if (list.ElementAt<TileClass>(i).Pos.X == playerPos.X && list.ElementAt<TileClass>(i).Pos.Y == playerPos.Y)
                            {
                                list.RemoveAt(i);
                            }
                        }
                    }
                    LevelPanel.Invalidate();

                }
            }
        }

        private void objectList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (objectList.SelectedIndex == (int)TileClass.ObjType.OBJ_BLOCK)
            {
                pictureBox.Image = Properties.Resources.Block;
            }

            else if (objectList.SelectedIndex == (int)TileClass.ObjType.OBJ_FLAG)
            {
                pictureBox.Image = Properties.Resources.Checkpoint;
            }

            else if (objectList.SelectedIndex == (int)TileClass.ObjType.OBJ_FLOOR)
            {
                pictureBox.Image = Properties.Resources.Floor;
            }

            else if (objectList.SelectedIndex == (int)TileClass.ObjType.OBJ_JUMPBOX)
            {
                pictureBox.Image = Properties.Resources.JumpBox;
            }

            else if (objectList.SelectedIndex == (int)TileClass.ObjType.OBJ_LAUNCHCANNON)
            {
                pictureBox.Image = Properties.Resources.LaunchCannon;
            }

            else if (objectList.SelectedIndex == (int)TileClass.ObjType.OBJ_RAMPS)
            {
                pictureBox.Image = Properties.Resources.Ramp;
            }

            else if (objectList.SelectedIndex == (int)TileClass.ObjType.OBJ_SPIKE)
            {
                pictureBox.Image = Properties.Resources.Spike;
            }

            else if (objectList.SelectedIndex == (int)TileClass.ObjType.OBJ_TURRET)
            {
                pictureBox.Image = Properties.Resources.Turret;
            }
        }

        private void gridX_ValueChanged(object sender, EventArgs e)
        {
            LevelGrid = new Point[(int)gridX.Value, LevelGrid.GetLength(1)];
            totalLevelSize = new Size(tileWH * LevelGrid.GetLength(0), tileWH * LevelGrid.GetLength(1));

            // check to see if the player if off the map. If so then move him along
            if (playerPos.X+tileWH > totalLevelSize.Width)
            {
                playerPos.X -= tileWH;
            }

            // check to see if any of the tiles are off the map. if so then remove them
            if (list.Count > 0)
            {
                int listSize = list.Count()-1;
                // To see what we have in the list and if it's greater than the new level size
                for (int i = listSize; i > -1; i--)
                {
                    int tempCheck = list.ElementAt<TileClass>(i).Pos.X / tileWH;
                    if (tempCheck+1 > LevelGrid.GetLength(0))
                    {
                        list.RemoveAt(i);
                    }
                }
            }
         
            LevelPanel.AutoScrollMinSize = new Size(LevelGrid.GetLength(0) * tileSize.Width, LevelGrid.GetLength(1) * tileSize.Height);

            LevelPanel.Invalidate();
        }

        private void gridY_ValueChanged(object sender, EventArgs e)
        {
            LevelGrid = new Point[LevelGrid.GetLength(0), (int)gridY.Value];
            totalLevelSize = new Size(tileWH * LevelGrid.GetLength(0), tileWH * LevelGrid.GetLength(1));

            // check to see if the player if off the map. If so then move him along
            if (playerPos.Y + tileWH > totalLevelSize.Height)
            {
                playerPos.Y -= tileWH;
            }

            // check to see if any of the tiles are off the map. if so then remove them
            if (list.Count > 0)
            {
                int listSize = list.Count() - 1;
                // To see what we have in the list and if it's greater than th new level size
                for (int i = listSize; i > -1; i--)
                {
                    int tempCheck = list.ElementAt<TileClass>(i).Pos.Y / tileWH;
                    if (tempCheck + 1 > LevelGrid.GetLength(1))
                    {
                        list.RemoveAt(i);
                    }
                }
            }

            LevelPanel.AutoScrollMinSize = new Size(LevelGrid.GetLength(0) * tileSize.Width, LevelGrid.GetLength(1) * tileSize.Height);

            LevelPanel.Invalidate();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            list.Clear();
            playerPos = new Point(0, 0);
            LevelPanel.Invalidate();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DialogResult result = DialogResult.No;

            if (list.Count > 0)
                result = MessageBox.Show("Save?", "Would you like to save?", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);

            if (result == DialogResult.Yes)
                saveToolStripMenuItem_Click(sender, e);
            else if (result == DialogResult.No)
                Environment.Exit(0);
        }

        private void tileWH_numBox_ValueChanged(object sender, EventArgs e)
        {
            tileWH = (int)tileWH_numBox.Value;

            tileSize = new Size(tileWH, tileWH);
            totalLevelSize = new Size(tileWH * LevelGrid.GetLength(0), tileWH * LevelGrid.GetLength(1));

            LevelPanel.AutoScrollMinSize = new Size(LevelGrid.GetLength(0) * tileSize.Width, LevelGrid.GetLength(1) * tileSize.Height);
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {      
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.Filter = "My Files(*.bin)|*.bin";
            if (DialogResult.OK == dlg.ShowDialog())
            {
                FileStream stream = new FileStream(Path.Combine(Application.StartupPath, dlg.FileName), FileMode.Create, FileAccess.Write);
                BinaryWriter fout = new BinaryWriter(stream);

                int listSize = list.Count() - 1;

                // Save out the list size
                fout.Write(list.Count() + 1);

                // Save out the player's position
                fout.Write((int)TileClass.ObjType.OBJ_PLAYER);
                fout.Write(playerPos.X);
                fout.Write(playerPos.Y);

                // Saved out in Binary in the order: Object's Type, Position X-axis, Position Y-axis
                for (int i = listSize; i > -1; i--)
                {
                    fout.Write(list.ElementAt<TileClass>(i).Type);
                    fout.Write(list.ElementAt<TileClass>(i).Pos.X);
                    fout.Write(list.ElementAt<TileClass>(i).Pos.Y);
                }

                // Save out the tile's Width and Height
                fout.Write(tileWH);

                // Save out the grids X and Y values
                fout.Write(LevelGrid.GetLength(0));
                fout.Write(LevelGrid.GetLength(1));

                fout.Close();
            }
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "My Files(*.bin)|*.bin";
            if (DialogResult.OK == dlg.ShowDialog())
            {
                FileStream stream = new FileStream(Path.Combine(Application.StartupPath, dlg.FileName), FileMode.Open);
                BinaryReader fin = new BinaryReader(stream);

                // Clear list before opening a new one
                list.Clear();

                int listSize = fin.ReadInt32() - 2; // Size of list - (player + list count)

                // Read in the player's position
                int temp = fin.ReadInt32();
                playerPos.X = fin.ReadInt32();
                playerPos.Y = fin.ReadInt32();

                for (int i = listSize; i > -1; i--)
                {
                    TileClass newTile = new TileClass();
                    newTile.Type = fin.ReadInt32();   
                    
                    //OBJ_BLOCK, OBJ_FLAG, OBJ_FLOOR, OBJ_JUMPBOX, OBJ_LAUNCHCANNON, OBJ_RAMPS, OBJ_SPIKE, OBJ_TURRET
                    switch (newTile.Type)
                    {
                        case (int)TileClass.ObjType.OBJ_BLOCK:
                            newTile.Bitmap = Properties.Resources.Block;
                            break;
                        case (int)TileClass.ObjType.OBJ_FLAG:
                            newTile.Bitmap = Properties.Resources.Checkpoint;
                            break;
                        case (int)TileClass.ObjType.OBJ_FLOOR:
                            newTile.Bitmap = Properties.Resources.Floor;
                            break;
                        case (int)TileClass.ObjType.OBJ_JUMPBOX:
                            newTile.Bitmap = Properties.Resources.JumpBox;
                            break;
                        case (int)TileClass.ObjType.OBJ_LAUNCHCANNON:
                            newTile.Bitmap = Properties.Resources.LaunchCannon;
                            break;
                        case (int)TileClass.ObjType.OBJ_RAMPS:
                            newTile.Bitmap = Properties.Resources.Ramp;
                            break;
                        case (int)TileClass.ObjType.OBJ_SPIKE:
                            newTile.Bitmap = Properties.Resources.Spike;
                            break;
                        case (int)TileClass.ObjType.OBJ_TURRET:
                            newTile.Bitmap = Properties.Resources.Turret;
                            break;
                        
                    }
                    int x = fin.ReadInt32();
                    int y = fin.ReadInt32();
                    newTile.Pos = new Point(x, y);
                    list.Add(newTile);
                }

                tileWH = fin.ReadInt32();
                int X = fin.ReadInt32();
                int Y = fin.ReadInt32();
                LevelGrid = new Point[X, Y];

                tileSize = new Size(tileWH, tileWH);
                totalLevelSize = new Size(tileWH * LevelGrid.GetLength(0), tileWH * LevelGrid.GetLength(1));

                LevelPanel.AutoScrollMinSize = new Size(LevelGrid.GetLength(0) * tileSize.Width, LevelGrid.GetLength(1) * tileSize.Height);
                gridX.Value = LevelGrid.GetLength(0);
                gridY.Value = LevelGrid.GetLength(1);

                tileWH_numBox.Value = tileWH;
                
                fin.Close();

                LevelPanel.Invalidate();
            }
        }

        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            list.Clear();
            playerPos = new Point(0, 0);
            LevelPanel.Invalidate();
        }
    }
}
